package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.jsola.core.Page;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IAttendOvertimeRuleDAO;
import org.jsola.hr.dto.AttendOvertimeRuleAddDTO;
import org.jsola.hr.dto.AttendOvertimeRuleUpdateDTO;
import org.jsola.hr.dto.AutoCalculOverTimeDTO;
import org.jsola.hr.dto.attendrule.NonWorkDayRuleDTO;
import org.jsola.hr.dto.attendrule.WorkDayRuleDTO;
import org.jsola.hr.entity.AttendOvertimeRuleDO;
import org.jsola.hr.entity.AttendPlanDO;
import org.jsola.hr.entity.AttendPunchDailyReportDO;
import org.jsola.hr.query.AttendOvertimeRuleQuery;
import org.jsola.hr.query.AttendPunchDailyReportQuery;
import org.jsola.hr.service.IAttendOvertimeRuleService;
import org.jsola.hr.service.IAttendPlanService;
import org.jsola.hr.service.IAttendPunchDailyReportService;
import org.jsola.hr.vo.AttendOvertimeRuleListVO;
import org.jsola.hr.vo.AttendOvertimeRuleVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrAttendOvertimeRuleServiceImpl")
public class AttendOvertimeRuleServiceImpl implements IAttendOvertimeRuleService {

    @Autowired
    private IAttendOvertimeRuleDAO attendOvertimeRuleDAO;
    @Autowired
    private IAttendPlanService attendPlanService;
    @Autowired
    private IAttendPunchDailyReportService attendPunchDailyReportService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public AttendOvertimeRuleVO save(AttendOvertimeRuleAddDTO attendOvertimeRuleAddDTO, TokenUser tokenUser) {
        // 转DO
        AttendOvertimeRuleDO attendOvertimeRuleDO = attendOvertimeRuleAddDTO.to(AttendOvertimeRuleDO.class);
        // 保存
        attendOvertimeRuleDO = save(attendOvertimeRuleDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return attendOvertimeRuleDO.to(AttendOvertimeRuleVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(AttendOvertimeRuleUpdateDTO attendOvertimeRuleUpdateDTO, TokenUser tokenUser) {
        //转DO
        AttendOvertimeRuleDO attendOvertimeRuleDO = attendOvertimeRuleUpdateDTO.to(AttendOvertimeRuleDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(attendOvertimeRuleDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... attendOvertimeRuleIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) attendOvertimeRuleIds);
    }


    @Override
    public AttendOvertimeRuleVO selectById(String attendOvertimeRuleId, String siteId) {
        AttendOvertimeRuleDO attendOvertimeRuleDO = selectDOById(attendOvertimeRuleId, siteId);
        if (attendOvertimeRuleDO == null) {
            return null;
        }
        return attendOvertimeRuleDO.to(AttendOvertimeRuleVO.class);
    }

    @Override
    public List<AttendOvertimeRuleListVO> select(AttendOvertimeRuleQuery attendOvertimeRuleQuery, String siteId) {
        List<AttendOvertimeRuleDO> attendOvertimeRuleDOList = selectDO(attendOvertimeRuleQuery, siteId);
        if(CollectionUtils.isEmpty(attendOvertimeRuleDOList)) {
            return attendOvertimeRuleDOList == null ? null : new ArrayList<>();
        }
        return attendOvertimeRuleDOList.stream()
                .map(attendOvertimeRuleDO -> attendOvertimeRuleDO.to(AttendOvertimeRuleListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(AttendOvertimeRuleQuery attendOvertimeRuleQuery, String siteId) {
        Example example = buildExample(attendOvertimeRuleQuery,siteId);
        return attendOvertimeRuleDAO.selectCountByExample(example);
    }

    @Override
    public Page<AttendOvertimeRuleListVO> selectPage(AttendOvertimeRuleQuery attendOvertimeRuleQuery, String siteId) {
        Example example = buildExample(attendOvertimeRuleQuery,siteId);
        Page<AttendOvertimeRuleDO> page = attendOvertimeRuleDAO.selectPageByExample(example,
                attendOvertimeRuleQuery.getPageNo(),
                attendOvertimeRuleQuery.getPageSize());

        return page.to(AttendOvertimeRuleListVO.class);
    }

    @Override
    public AttendOvertimeRuleDO selectDOById(String attendOvertimeRuleId, String siteId) {
        return listById(attendOvertimeRuleId, siteId);
    }

    @Override
    public List<AttendOvertimeRuleDO> selectDO(AttendOvertimeRuleQuery attendOvertimeRuleQuery, String siteId) {
        Example example = buildExample(attendOvertimeRuleQuery,siteId);
        return attendOvertimeRuleDAO.selectByExample(example);
    }

    @Override
    public int deleteByAttendPlanId(String attendPlanId, String siteId) {
        AttendOvertimeRuleQuery attendOvertimeRuleQuery = new AttendOvertimeRuleQuery();
        attendOvertimeRuleQuery.setAttendPlanId(attendPlanId);
        Example example = buildExample(attendOvertimeRuleQuery, siteId);
        return attendOvertimeRuleDAO.deleteByExample(example);
    }

    @Override
    public int autoCalculOverTime(AutoCalculOverTimeDTO autoCalculOverTimeDTO, TokenUser tokenUser) {

        // 根据考勤规则ID查询
        AttendPlanDO attendPlanDO = attendPlanService.selectDOById(autoCalculOverTimeDTO.getAttendPlanId(), tokenUser.getSiteId());

        // 加班规则 ; 1-以加班申请为准,2-以打卡时间为准,3-以加班申请核算打卡记录
        if (attendPlanDO.getOvertimeRule() != 2) {
            return 0;
        }
        // 查询加班规则
        AttendOvertimeRuleQuery attendOvertimeRuleQuery = new AttendOvertimeRuleQuery();
        attendOvertimeRuleQuery.setAttendPlanId(autoCalculOverTimeDTO.getAttendPlanId());
        List<AttendOvertimeRuleDO> attendOvertimeRuleList = this.selectDO(attendOvertimeRuleQuery, tokenUser.getSiteId());
        if (attendOvertimeRuleList.size() <= 0) {
            return 0;
        }

        // 加班时长(分钟)
        int punchTimeInt = Integer.valueOf(autoCalculOverTimeDTO.getPunchTime().replace(":","")).intValue();
        int offWorkTimeInt = Integer.valueOf(autoCalculOverTimeDTO.getOffWorkTime().replace(":","")).intValue();
        if (offWorkTimeInt >= punchTimeInt) {
            return 0;
        }

        int overtimeMins = punchTimeInt - offWorkTimeInt;

        AttendOvertimeRuleDO attendOvertimeRuleDO = attendOvertimeRuleList.get(0);

        int overtime = 0;
        // 日期类型 1-工作日,2-休息日,3-法定节假日
        // 如果是工作日加班
        if (autoCalculOverTimeDTO.getDateType() == 1) {

            // 是否允许工作日加班
            if (StringUtils.isBlank(attendOvertimeRuleDO.getWorkDayRuleJson())) {
                return 0;
            }

            WorkDayRuleDTO workDayRuleDTO = JSON.parseObject(attendOvertimeRuleDO.getWorkDayRuleJson(), WorkDayRuleDTO.class);
            if (workDayRuleDTO != null) {
                // 加班开始时间： 下班后 x 分钟开始计算加班
                if (overtimeMins <= workDayRuleDTO.getStartMinutes()) {
                    return 0;
                }
                // 最短加班时长： x 分钟  不足30分钟记录为未加班
                overtime = overtimeMins - workDayRuleDTO.getShortMinutes();
                if (overtime <= workDayRuleDTO.getShortMinutes()) {
                    return 0;
                }
                // 最长加班时长：x 分钟 超过则记录为x分钟
                if (overtime >= workDayRuleDTO.getLongestMinutes()) {
                    overtime = workDayRuleDTO.getLongestMinutes();
                }
            }
        }
        // 如果是非工作日加班
        else {
            // 是否允许非工作日加班
            if (StringUtils.isBlank(attendOvertimeRuleDO.getNonWorkDayRuleJson())) {
                return 0;
            }
            NonWorkDayRuleDTO nonWorkDayRuleDTO = JSON.parseObject(attendOvertimeRuleDO.getNonWorkDayRuleJson(), NonWorkDayRuleDTO.class);
            if (nonWorkDayRuleDTO == null) {
                return 0;
            }
            overtime = overtimeMins;

            if (overtimeMins < nonWorkDayRuleDTO.getShortMinutes()) {
                return 0;
            }
            if (overtimeMins > nonWorkDayRuleDTO.getLongestMinutes()) {
                overtime = nonWorkDayRuleDTO.getLongestMinutes();
            }
        }

        // 考勤打卡日报表 修改加班时长
        AttendPunchDailyReportQuery attendPunchDailyReportQuery = new AttendPunchDailyReportQuery();
        attendPunchDailyReportQuery.setAttendPlanId(autoCalculOverTimeDTO.getAttendPlanId());
        attendPunchDailyReportQuery.setEmpInfoId(autoCalculOverTimeDTO.getEmpInfoId());
        attendPunchDailyReportQuery.setYearly(autoCalculOverTimeDTO.getYearly());
        attendPunchDailyReportQuery.setMonthly(autoCalculOverTimeDTO.getMonthly());
        attendPunchDailyReportQuery.setDaily(autoCalculOverTimeDTO.getDaily());
        List<AttendPunchDailyReportDO> dailyReportList = attendPunchDailyReportService.selectDO(attendPunchDailyReportQuery, tokenUser.getSiteId());
        if (dailyReportList.size() > 0) {
            AttendPunchDailyReportDO attendPunchDailyReportDO = new AttendPunchDailyReportDO();
            attendPunchDailyReportDO.setId(dailyReportList.get(0).getId());
            BigDecimal overB = new BigDecimal(overtime).divide(new BigDecimal("60")).setScale(1, BigDecimal.ROUND_DOWN);
            attendPunchDailyReportDO.setOvertimeHours(dailyReportList.get(0).getOvertimeHours().add(overB));
            attendPunchDailyReportService.updateByIdSelective(attendPunchDailyReportDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }


        return 1;
    }

    /**
     * 根据查询参数，构建example

     * @param attendOvertimeRuleQuery 查询参数
     * @param siteId 所属站点id
     * @return example
     */
    private Example buildExample(AttendOvertimeRuleQuery attendOvertimeRuleQuery, String siteId) {
        Example example = new Example(AttendOvertimeRuleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (attendOvertimeRuleQuery.getAttendPlanId() != null) {
            example.and().andEqualTo("attendPlanId", attendOvertimeRuleQuery.getAttendPlanId());
        }
        if (attendOvertimeRuleQuery.getOvertimeType() != null) {
            example.and().andEqualTo("overtimeType", attendOvertimeRuleQuery.getOvertimeType());
        }
        if (attendOvertimeRuleQuery.getWorkDayRuleJson() != null) {
            example.and().andEqualTo("workDayRuleJson", attendOvertimeRuleQuery.getWorkDayRuleJson());
        }
        if (attendOvertimeRuleQuery.getNonWorkDayRuleJson() != null) {
            example.and().andEqualTo("nonWorkDayRuleJson", attendOvertimeRuleQuery.getNonWorkDayRuleJson());
        }
        // 排序
        ExampleKit.setExampleOrder(example,attendOvertimeRuleQuery.getOrders());
        return example;
    }
}




